home *** CD-ROM | disk | FTP | other *** search
/ AI Game Programming Wisdom / AIGameProgrammingWisdom.iso / SourceCode / 02 Useful Techniques / 08 Zarozinski / src / ffllapi / MemberFuncBase.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-11-13  |  11.6 KB  |  513 lines

  1. //
  2. // File:    MemberFuncBase.cpp
  3. //
  4. // Purpose:    This is the base class for the membership functions
  5. //
  6. // Copyright ⌐ 1999-2001 Louder Than A Bomb! Software
  7. //
  8. // This file is part of the FFLL (Free Fuzzy Logic Library) project (http://ffll.sourceforge.net)
  9. // It is released under the BSD license, see http://ffll.sourceforge.net/license.txt for the full text.
  10. //
  11.  
  12. // include files
  13. #include "FuzzySetBase.h"
  14. #include "MemberFuncBase.h"
  15. #include "FuzzyModelBase.h"
  16. #include "FuzzyVariableBase.h"
  17.  
  18. #ifdef  _DEBUG 
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23. //
  24. // Function:    MemberFuncBase()
  25. // 
  26. // Purpose:        Constructor
  27. //
  28. // Arguments:
  29. //
  30. //        FuzzySetBase* _parent - Set this member function is part of
  31. //
  32. // Returns:
  33. //
  34. //        none
  35. //
  36. // Author:    Michael Zarozinski
  37. // Date:    5/99
  38. // 
  39. // Modification History
  40. // Author    Date        Modification
  41. // ------    ----        ------------
  42. //
  43. //
  44. MemberFuncBase::MemberFuncBase(FuzzySetBase* _parent) : FFLLBase(_parent)  
  45. {
  46.  
  47.     // NOTE: don't call init() from here cuz it's virtual and it calls virtual functions which
  48.     // aren't called the way we want from the constructor
  49.  
  50.     nodes = NULL;
  51.   
  52.     values = NULL; 
  53.  
  54.     ramp = MemberFuncBase::RAMP::NONE; // not a ramp (at this point)
  55.  
  56. } // end MemberFuncBase::MemberFuncBase()
  57.  
  58.  
  59. //
  60. // Function:    ~MemberFuncBase()
  61. // 
  62. // Purpose:        Destructor
  63. //
  64. // Arguments:
  65. //
  66. //        none
  67. //
  68. // Returns:
  69. //
  70. //        none
  71. //
  72. // Author:    Michael Zarozinski
  73. // Date:    5/99
  74. // 
  75. // Modification History
  76. // Author    Date        Modification
  77. // ------    ----        ------------
  78. //
  79. //
  80. MemberFuncBase::~MemberFuncBase(void)
  81. {
  82.     if (nodes != NULL)
  83.         delete[] nodes;
  84.  
  85.      dealloc_values_array();
  86.  
  87.     nodes = NULL;
  88.  
  89. } // end MemberFuncBase::~MemberFuncBase()
  90.  
  91. //
  92. // Function:    init()
  93. // 
  94. // Purpose:        Initialization for the member func that is specific
  95. //                to the type of member function. This is a VIRTUAL 
  96. //                function and as such must be called AFTER the object
  97. //                is created (virtual funcs can not be called from
  98. //                the constructor).
  99. //
  100. // Arguments:
  101. //
  102. //        none
  103. //
  104. // Returns:
  105. //
  106. //        void
  107. //
  108. // Author:    Michael Zarozinski
  109. // Date:    5/99
  110. // 
  111. // Modification History
  112. // Author    Date        Modification
  113. // ------    ----        ------------
  114. //
  115. //
  116.  void MemberFuncBase::init( )
  117. {
  118.     // allocate the values array
  119.     alloc_values_array();
  120.  
  121.     // zero out values...
  122.     clear_values( );
  123.  
  124. } // end MemberFuncBase::init();
  125.  
  126.  
  127.  
  128. //
  129. // Function:    set_ramp()
  130. // 
  131. // Purpose:        Set the ramp status for this member func. This is a VIRTUAL func
  132. //                so member funcs like the Singleton can override this.
  133. //                A ramp is a membership function that has the 'y' axis
  134. //                as one of it's sides. For example a normal trapezoid memberhip
  135. //                function would look like this:
  136. //                                       ___
  137. //              Normal Trapezoid:       /   \
  138. //                                       ___
  139. //              Left Ramp Trapezoid:    |   \ 
  140. //                                       ___
  141. //              Right Ramp Trapezoid:   /   |  
  142. //
  143. // Arguments:
  144. //
  145. //        int left_right_ind        -    indicates if we're making a left (1) or right (0) ramp
  146. //        int hi_lo_ind            -    indicates if we're creating (1) or removing (0) ramp
  147. //
  148. // Returns:
  149. //
  150. //        void
  151. //
  152. // Author:    Michael Zarozinski
  153. // Date:    7/99
  154. // 
  155. // Modification History
  156. // Author    Date        Modification
  157. // ------    ----        ------------
  158. //
  159. //
  160.  
  161. void  MemberFuncBase::set_ramp(int hi_lo_ind, int left_right_ind)
  162. {
  163.     // set the type of ramp for this term
  164.      if (hi_lo_ind == 0)
  165.         ramp = MemberFuncBase::RAMP::NONE;
  166.     else
  167.         {
  168.         if (left_right_ind)
  169.             ramp = MemberFuncBase::RAMP::LEFT;
  170.         else
  171.             ramp = MemberFuncBase::RAMP::RIGHT;
  172.         }
  173.  
  174.     calc(); // re-calc 'y' values
  175.  
  176. } // end MemberFuncBase::set_ramp()
  177.  
  178.  
  179. //
  180. // Function:    move()
  181. // 
  182. // Purpose:        Moves ALL the nodes for the member func by the delta passed in.
  183. //
  184. // Arguments:
  185. //
  186. //        int x_delta - how many 'x' elements (in the values[] array) to move each node by 
  187. //
  188. // Returns:
  189. //
  190. //        void
  191. //
  192. // Author:    Michael Zarozinski
  193. // Date:    7/99
  194. // 
  195. // Modification History
  196. // Author    Date        Modification
  197. // ------    ----        ------------
  198. //
  199. //
  200. void MemberFuncBase::move(int x_delta) 
  201. {
  202.  
  203.     if (x_delta == 0)
  204.         return; // nothing to do!
  205.  
  206.     // move all the nodes... 
  207.  
  208.     // we need to be careful about the order we move them in.
  209.     // if they are being move to the right (positive offset) we need to
  210.     // move the last point and work our way to the first point so we don't
  211.     // cross any points if the offset is large.
  212.     // likewize if we're moving to the left (negative offset) move them in
  213.     // order (first to last)
  214.  
  215.     int start, end, increment;    // values that determine how we loop
  216.      int node_count = get_node_count();
  217.  
  218.     if (x_delta < 0)
  219.         {
  220.         // moving to the left
  221.         start = 0;
  222.         end = node_count;
  223.         increment = 1;
  224.  
  225.         // adjust the delta so we don't "collapse" the term
  226.         
  227.         if (nodes[0].x + x_delta < 0)
  228.             x_delta = -nodes[0].x;
  229.  
  230.         } // end if offset negative
  231.     else
  232.         {
  233.         // offset is positive
  234.         start = node_count - 1;
  235.         end = -1;
  236.         increment = -1;
  237.         if (nodes[node_count - 1].x + x_delta > FuzzyVariableBase::get_x_array_max_idx())
  238.             x_delta = ( FuzzyVariableBase::get_x_array_max_idx()) - nodes[node_count - 1].x;
  239.  
  240.         } // end if offset positive
  241.  
  242.     // now move them all (note the 'y' direction is invariant when moving all nodes at once)
  243.  
  244.     for (int i = start; i != end; i += increment)
  245.         {
  246.           move_node(i, nodes[i].x + x_delta, nodes[i].y );
  247.  
  248.         } // end loop through nodes
  249.  
  250. } // end MemberFuncBase::move()
  251.  
  252.  
  253.  
  254. //
  255. // Function:    save_to_fcl_file()
  256. // 
  257. // Purpose:        Virtual func to write out the FCL (Fuzzy Control Language) for this membership function.
  258. //                This is the "membership_function" part of the set's information which
  259. //                has the format (as defined by the IEC 61131-7 International Standard):
  260. //
  261. //                    TERM term_name:= membership_function;
  262. //
  263. //                Each node is written out as "(<x value>, <y value>)" where the values
  264. //                may or may not have a decimal point. NOTE that singletons are special 
  265. //                and can be written out as just the x value. But we don't need to worry
  266. //                about most of that here cuz this is a VIRTUAL func so if it's a singleton
  267. //                that version will deal with it explicitly.
  268. //
  269. // Arguments:
  270. //
  271. //        std::ofstream& file_contents - STL stream to write out to a file
  272. //
  273. // Returns:
  274. //
  275. //        void
  276. //
  277. // Author:    Michael Zarozinski
  278. // Date:    9/01
  279. // 
  280. // Modification History
  281. // Author    Date        Modification
  282. // ------    ----        ------------
  283. //
  284. //
  285.  
  286. void MemberFuncBase::save_to_fcl_file(std::ofstream& file_contents)
  287. {
  288.  
  289.     char  val[6];    // temp string to hold the string version of a number
  290.     int precision ;    // how many decimal places to show  
  291.  
  292.      // list the points...
  293.     for (int i = 0; i < get_node_count(); i++)
  294.         {
  295.         // convert the index in the values array to an 'x' value
  296.          RealType fvalue = get_parent()->convert_idx_to_value(get_node_x(i));
  297.  
  298.         // if there is a decimal point for this, display only 2 decimal places,
  299.         // else don't display any (this just makes the FCL file easier to read)
  300.         if (fmod(fvalue, 1) == 0)
  301.             precision = 0;
  302.         else
  303.             precision = 2;
  304.  
  305.          // trim 'x' value to the specified precision
  306.         sprintf( val, "%.*lf", precision, fvalue );
  307.  
  308.          file_contents << "(" <<  val << ", ";
  309.  
  310.         // convert to 'y' coordinates
  311.         fvalue = static_cast<RealType>(get_node_y(i)) / static_cast<RealType>(FuzzyVariableBase::get_dom_array_max_idx());
  312.  
  313.         if (fmod(fvalue, 1) == 0)
  314.             precision = 0;
  315.         else
  316.             precision = 2;
  317.  
  318.         sprintf( val, "%.*lf", precision, fvalue );
  319.         
  320.         file_contents << val << ") ";
  321.  
  322.         } // end loop through nodes
  323.  
  324.     // add ending semi-colon
  325.     file_contents << ";";
  326.  
  327. } // end MemberFuncBase::save_to_file()
  328.  
  329. /////////////////////////////////////////////////////////////////////
  330. ////////// Trivial Functions That Don't Require Headers /////////////
  331. /////////////////////////////////////////////////////////////////////
  332.  
  333. int MemberFuncBase::alloc_values_array()
  334. {
  335.     values = new DOMType[ FuzzyVariableBase::get_x_array_count()];
  336.  
  337.     if (values == NULL)
  338.         {
  339.         set_msg_text(ERR_ALLOC_MEM);
  340.         return -1;
  341.         }
  342.  
  343.     return 0;
  344.  
  345. } // end MemberFuncBase::alloc_values_array()
  346.  
  347. void MemberFuncBase::dealloc_values_array()
  348. {
  349.      if (values != NULL)
  350.         delete[] values;
  351.  
  352.     values = NULL;
  353.  
  354. } // end MemberFuncBase::dealloc_values_array()
  355.  
  356. void MemberFuncBase::move_node(int idx, _point pt) 
  357. {
  358.     move_node(idx, pt.x, pt.y);    
  359. };
  360.  
  361. void MemberFuncBase::move_node(int idx, int x, int y)  
  362. {
  363.      set_node(idx, x, y);
  364.  
  365. };
  366.  
  367. void MemberFuncBase::clear_values()
  368.     memset(values, 0,  FuzzyVariableBase::get_x_array_count() * sizeof(DOMType));
  369.  
  370. };
  371.  
  372. int MemberFuncBase::alloc_nodes(int node_count)
  373. {
  374.     nodes = new NodePoint[node_count];
  375.  
  376.     if (nodes == NULL)
  377.         {
  378.         set_msg_text(ERR_ALLOC_MEM);
  379.         return -1;
  380.         }
  381.  
  382.     // initialize 
  383.     for (int i = 0; i < node_count; i++) 
  384.          nodes[i].x = nodes[i].y = 0;
  385.  
  386.     return 0;
  387. };
  388.  
  389. int MemberFuncBase::get_start_x(void) const 
  390. {
  391.     return(nodes[0].x);
  392. };
  393. int MemberFuncBase::get_center_x(void) const 
  394. {
  395.     return nodes[0].x + ((nodes[get_node_count() - 1].x - nodes[0].x)/2);
  396. }; 
  397.  
  398. NodePoint MemberFuncBase::get_node(int idx) const 
  399. {
  400.     return nodes[idx];
  401. };
  402.  
  403. int MemberFuncBase::get_node_x(int idx) const 
  404. {
  405.     return nodes[idx].x;
  406. };
  407. int MemberFuncBase::get_node_y(int idx) const 
  408. {
  409.     return nodes[idx].y;
  410. };
  411. FuzzySetBase* MemberFuncBase::get_parent() const 
  412. {
  413.     return static_cast<FuzzySetBase*>(FFLLBase::get_parent());
  414. };
  415.  
  416. int MemberFuncBase::get_ramp() const
  417. {
  418.     return ramp;
  419. };
  420.  
  421. DOMType MemberFuncBase::get_dom(int idx)
  422. {
  423.  
  424.     assert(idx >= 0);
  425.     assert(idx < FuzzyVariableBase::get_x_array_count());
  426.  
  427.     // make sure index is within range
  428.     if (idx < 0)
  429.         idx = 0;
  430.     if (idx > FuzzyVariableBase::get_x_array_max_idx())
  431.         idx = FuzzyVariableBase::get_x_array_max_idx();
  432.     
  433.     return values[idx];
  434.  
  435. };
  436.  
  437. int MemberFuncBase::get_end_x(void) const
  438. {
  439.     return(nodes[get_node_count() - 1].x);
  440. }  
  441.   
  442. RealType  MemberFuncBase::get_left_x() const 
  443. {
  444.     return get_parent()->get_left_x();
  445. };
  446.     
  447. DOMType MemberFuncBase::get_value(int idx) const 
  448.     assert(idx >= 0);
  449.     assert(idx < FuzzyVariableBase::get_x_array_count());
  450.         
  451.     // make sure index is within range
  452.     if (idx < 0)
  453.         idx = 0;
  454.     if (idx > FuzzyVariableBase::get_x_array_max_idx())
  455.         idx = FuzzyVariableBase::get_x_array_max_idx();
  456.  
  457.     return values[idx]; 
  458. };
  459.  
  460. int MemberFuncBase::set_value(int idx, DOMType val) 
  461. {
  462.     // this value accepts a value between 0 and DOM max
  463.  
  464.     assert(idx >= 0);
  465.     assert(idx < FuzzyVariableBase::get_x_array_count());
  466.  
  467.     // make sure index is within range
  468.     if (idx < 0)
  469.         idx = 0;
  470.     if (idx > FuzzyVariableBase::get_x_array_max_idx())
  471.         idx = FuzzyVariableBase::get_x_array_max_idx();
  472.  
  473.     values[idx] = val;
  474.  
  475.     return 0;
  476. };
  477.  
  478. int MemberFuncBase::set_value(int idx, RealType val) 
  479. {
  480.     // this version takes a value from 0 to 1 and maps it to a value between 0 and DOM max
  481.  
  482.     // mapp the float to the values[] array makeing sure it doen't go over
  483.     // the DOM max
  484.  
  485.     assert(val >= 0.0f);
  486.     assert(val <= 1.0f);
  487.  
  488.     DOMType y = (static_cast<RealType>(FuzzyVariableBase::get_dom_array_max_idx()) * val) + 0.5; // add .5 to account for rounding
  489.  
  490.     assert(y >= 0);
  491.     assert(y <= FuzzyVariableBase::get_dom_array_max_idx());
  492.  
  493.     if (y < 0)
  494.         y = 0;
  495.     if (y > FuzzyVariableBase::get_dom_array_max_idx())
  496.         y = FuzzyVariableBase::get_dom_array_max_idx();
  497.  
  498.     assert(idx >= 0);
  499.     assert(idx < FuzzyVariableBase::get_x_array_count());
  500.  
  501.     // make sure index is within range
  502.     if (idx < 0)
  503.         idx = 0;
  504.     if (idx > FuzzyVariableBase::get_x_array_max_idx())
  505.         idx = FuzzyVariableBase::get_x_array_max_idx();
  506.  
  507.     values[idx] = y;
  508.  
  509.     return 0;
  510. };
  511.